Louis Szeto and Jacob Craven

In [1]:
# Importing libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from plotly import tools
# import plotly.plotly as py
import chart_studio.plotly
from plotly.offline import init_notebook_mode, iplot
init_notebook_mode(connected=True)
import plotly.graph_objs as go
import plotly.figure_factory as ff
from IPython.display import HTML, Image
import plotly.express as px
px.set_mapbox_access_token(open(".mapbox_token").read())
import datetime 
In [2]:
#load data
import pandas as pd
birds = pd.read_csv("bird_tracking.csv")
In [3]:
birds.head()
Out[3]:
altitude date_time device_info_serial direction latitude longitude speed_2d bird_name
0 71 2013-08-15 00:18:08+00 851 -150.469753 49.419859 2.120733 0.150000 Eric
1 68 2013-08-15 00:48:07+00 851 -136.151141 49.419880 2.120746 2.438360 Eric
2 68 2013-08-15 01:17:58+00 851 160.797477 49.420310 2.120885 0.596657 Eric
3 73 2013-08-15 01:47:51+00 851 32.769360 49.420359 2.120859 0.310161 Eric
4 69 2013-08-15 02:17:42+00 851 45.191230 49.420331 2.120887 0.193132 Eric
In [4]:
birds.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 61920 entries, 0 to 61919
Data columns (total 8 columns):
altitude              61920 non-null int64
date_time             61920 non-null object
device_info_serial    61920 non-null int64
direction             61477 non-null float64
latitude              61920 non-null float64
longitude             61920 non-null float64
speed_2d              61477 non-null float64
bird_name             61920 non-null object
dtypes: float64(4), int64(2), object(2)
memory usage: 3.8+ MB

The Average Speed Order of Three Birds:

In [5]:
speed = birds.groupby('bird_name')['speed_2d'].mean().to_frame()
print(speed)
           speed_2d
bird_name          
Eric       2.300545
Nico       2.908726
Sanne      2.450434
In [6]:
fig = px.bar(speed, y= "speed_2d")
fig.show()

We can see Nico has the highest average speed of 2.9, Eric has the lowest average speed of 2.3

We can check on the difference between day time speed and night time speed.

In [7]:
birds['time'] = pd.to_datetime(birds['date_time']).dt.time
night_bird = birds[(birds.time >= datetime.time(18,0,0)) | (birds.time <= datetime.time(5,0,0))]
night_bird_speed = night_bird.groupby('bird_name')['speed_2d'].mean().to_frame()
night_bird_speed
Out[7]:
speed_2d
bird_name
Eric 1.850162
Nico 2.527471
Sanne 2.232972
In [8]:
day_bird = birds[(birds.time <= datetime.time(18,0,0))  & (birds.time >= datetime.time(5,0,0))]
day_bird_speed = day_bird.groupby('bird_name')['speed_2d'].mean().to_frame()
day_bird_speed
Out[8]:
speed_2d
bird_name
Eric 2.583118
Nico 3.144957
Sanne 2.583575

From the result, the speed order doesn't change in day or night time. Eric has the largest speed difference among three birds of 0.73

This is the map of all movement of the birds

In [9]:
px.set_mapbox_access_token(open(".mapbox_token").read())
fig = px.scatter_mapbox(birds, lat="latitude", lon="longitude", color = "bird_name",
                  color_continuous_scale=px.colors.cyclical.IceFire,zoom=5)
fig.show()

We can tell that Nico has the largest difference of latitude while Eric has the smallest difference overall.

In [10]:
birds['month'] = pd.to_datetime(birds['date_time']).dt.month
birds['year'] = pd.to_datetime(birds['date_time']).dt.year
birds['day'] = pd.to_datetime(birds['date_time']).dt.day
birds.month.unique()
Out[10]:
array([ 8,  9, 10, 11, 12,  1,  2,  3,  4])

In the Following, I would like analysis the movement of all three birds, espiscally toward the south.
Below is a map of three bird movement in August

In [11]:
birds_AUG = birds[ (birds['month']== 8)]
fig = px.scatter_mapbox(birds_AUG, lat="latitude", lon="longitude", color = "bird_name",
                  color_continuous_scale=px.colors.cyclical.IceFire,zoom=5)
fig.show()                 

From this map, we can see Sanne already have a different pattern than the other two where other two staying at the North France. However we haven't know the direction of Sanne(i.e. going south or going north) Below is a map of Sanne in August

In [12]:
birds_Sanne_AUG = birds[ (birds['month']== 8) & (birds.bird_name == "Sanne")]
fig = px.scatter_mapbox(birds_Sanne_AUG, lat="latitude", lon="longitude", color = "day",
                  color_continuous_scale=px.colors.cyclical.IceFire,zoom=5)
fig.show()  

Now we know he is going to the South in August and starts to migrate on about 28th of August

In [13]:
birds_SEPT = birds[ (birds['month']== 9)]
fig = px.scatter_mapbox(birds_SEPT, lat="latitude", lon="longitude", color = "bird_name",
                  color_continuous_scale=px.colors.cyclical.IceFire,zoom=5)
fig.show()  

Above is a map of September. We can see Sanne already reached its distination while the other two remain in North France

In [14]:
birds_NOV = birds[ (birds['month']== 11)]
fig = px.scatter_mapbox(birds_NOV, lat="latitude", lon="longitude", color = "bird_name",
                  color_continuous_scale=px.colors.cyclical.IceFire,zoom=5)
fig.show() 

Above is a map of November, both Eric and Nico start to move south while Nico move faster than Eric. But Eric already reach its distination Morocco, Nico haven't.

In [15]:
birds_Dec= birds[ (birds['month']== 12)]
fig = px.scatter_mapbox(birds_Dec, lat="latitude", lon="longitude", color = "bird_name",
                  color_continuous_scale=px.colors.cyclical.IceFire,zoom=5)
fig.show() 

Finally in December, Nico also reach its distination of migration and take a break from the winter. In conclusion, Sanner start moving in August and arrives its distination earliest. Both Eric and Nico start moving in November and Eric arrives its distination ealier than Nico.

In [17]:
birds_alt = birds
def to_positive(val):
    if val < 0 or val == 0:
        val = 1
    return val
birds_alt['altitude'] = birds_alt.apply(lambda x: to_positive(x.altitude), axis = 1)
In [18]:
fig = px.scatter_mapbox(birds_alt, lat="latitude", lon="longitude", color = "bird_name", size = 'altitude',
                  color_continuous_scale=px.colors.cyclical.IceFire,zoom=5)
fig.show()  

Here we can see the altitude for each bird over the course of each of their migration.

Similarly, we can look at speed to see where they were flying the fastest. We can then compare the two to see how altitude and speed are related.

In [26]:
birds_speed = birds
def to_positive(val):
    if val < 0 or val == 0:
        val = 1
    return val
birds_speed['speed_2d'] = birds_speed.apply(lambda x: to_positive(x.speed_2d), axis = 1)
birds_speed['speed_2d'] = birds_speed['speed_2d'].fillna(1)
In [27]:
fig = px.scatter_mapbox(birds, lat="latitude", lon="longitude", color = "bird_name", size = 'speed_2d',
                  color_continuous_scale=px.colors.cyclical.IceFire,zoom=5)
fig.show()  

We can then limit the dataframe to just one bird to compare speed by altitude per bird using size and color.

In [28]:
birds_eric = birds.loc[lambda d: d['bird_name']=='Eric']
birds_eric['altitude'] = birds_eric.apply(lambda x: to_positive(x.altitude), axis = 1)
birds_eric['speed_2d'] = birds_eric.apply(lambda x: to_positive(x.speed_2d), axis = 1)
In [30]:
fig = px.scatter_mapbox(birds_eric, lat="latitude", lon="longitude", color = "speed_2d", size = 'altitude',
                  color_continuous_scale=px.colors.cyclical.IceFire,zoom=5)
fig.show()  

It looks like Eric remains at a pretty consistent speed and altitude by this graph, with a couple spikes likely due to diving.

In [31]:
birds_sanne = birds.loc[lambda d: d['bird_name']=='Sanne']
birds_sanne['altitude'] = birds_sanne.apply(lambda x: to_positive(x.altitude), axis = 1)
birds_sanne['speed_2d'] = birds_sanne.apply(lambda x: to_positive(x.speed_2d), axis = 1)
In [32]:
fig = px.scatter_mapbox(birds_sanne, lat="latitude", lon="longitude", color = "speed_2d", size = 'altitude',
                  color_continuous_scale=px.colors.cyclical.IceFire,zoom=5)
fig.show()  

Sanne interestingly flies way higher over Portugal than anywhere else, while also maintaining a somewhat consistent speed

In [33]:
birds_nico = birds.loc[lambda d: d['bird_name']=='Nico']
birds_nico['altitude'] = birds_nico.apply(lambda x: to_positive(x.altitude), axis = 1)
birds_nico['speed_2d'] = birds_nico.apply(lambda x: to_positive(x.speed_2d), axis = 1)
In [34]:
fig = px.scatter_mapbox(birds_nico, lat="latitude", lon="longitude", color = "speed_2d", size = 'altitude',
                  color_continuous_scale=px.colors.cyclical.IceFire,zoom=5)
fig.show()  

Nico flies much lower than the others by the looks of it, again rising over the Spain/Portugal area like Sanne did. But Nico flies much faster ofer the water off the coast of France than the others.